﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Moon.Sql
{
    public class QueryableUnionProvide : IQueryableUnion
    {
        private IDatabase Database;
        private List<SqlBuilderResult> Unions;

        public QueryableUnionProvide(IDatabase _Database)
        {
            Database = _Database;
            Unions = new List<SqlBuilderResult>();
        }

        private SqlBuilderResult _ToList()
        {
            if (Unions.Count == 0)
            {
                return null;
            }
            DynamicParameters parameters = new DynamicParameters();
            StringBuilder sbSql = new StringBuilder();
            foreach (var item in Unions)
            {
                sbSql.Append(item.Sql);
                parameters.Add(item.DynamicParameters);
            }
            string sql = sbSql.ToString().TrimEnd("union all\r\n".ToArray()).TrimEnd("union\r\n".ToArray());
            return new SqlBuilderResult()
            {
                Sql = sql,
                DynamicParameters = parameters
            };
        }

        public List<T> ToList<T>()
        {
            var result = _ToList();
            Unions.Clear();
            return Database.Query<T>(result.Sql, result.DynamicParameters);
        }

        public async Task<List<T>> ToListAsync<T>()
        {
            var result = _ToList();
            Unions.Clear();
            return await Database.QueryAsync<T>(result.Sql, result.DynamicParameters);
        }

        public IQueryableUnion Union<T>(IQueryable<T> queryable)
        {
            SqlBuilderResult result = ToSql<T>(queryable);
            result.Sql = result.Sql + " union\r\n";
            Unions.Add(result);
            return this;
        }

        public IQueryableUnion UnionAll<T>(IQueryable<T> queryable)
        {
            SqlBuilderResult result = ToSql<T>(queryable);
            result.Sql = result.Sql + " union all\r\n";
            Unions.Add(result);
            return this;
        }

        private SqlBuilderResult ToSql<T>(IQueryable<T> queryable)
        {
            SqlBuilderResult result = queryable.ToSql();
            int index = Unions.Count + 1;
            DynamicParameters parameters = new DynamicParameters();
            foreach (KeyValuePair<string, ParamInfo> item in result.DynamicParameters.Get())
            {
                result.Sql = result.Sql
                    .Replace($"@{item.Key}", $"@{item.Key}_{index}")
                    .Replace($":{item.Key}", $":{item.Key}_{index}");
                parameters.Add($"{item.Key}_{index}", item.Value.Value);
            }
            result.DynamicParameters = parameters;
            return result;
        }
    }
}
